#pragma once

#include <vector>
#include <string>

#include "position.h"
#include "funds.h"

#include "dbg.h"

#ifdef PUNCH_MSGPACK
#include <msgpack.hpp>
#endif

namespace mdtx::punch::tradesim
{

    /**
     * @brief Record event
     *
     */
    enum struct RecordEvent : char
    {
        submit,
        match,
        cancel
    };

    /**
     * @brief Records trading events and callbacks
     *
     * @tparam QT quote type
     */
    template <typename QT>
    class BaseRecord
    {
    public:
        using time_type = typename QT::time_type;
        using id_type = typename QT::id_type;
        using quant_type = typename QT::quant_type;

        using pos_rec = typename Position<QT>::PositionT;
        using funds_rec = typename Funds<QT>::FundsT;

        struct RecordT
        {
            time_type time;
            id_type cli_id, ins_id, seq_id;
            quant_type price, vol, tnvr;
            RecordEvent event;
            bool buy, agr;

#ifdef PUNCH_MSGPACK
            MSGPACK_DEFINE_ARRAY(time,
                                 cli_id, ins_id, seq_id,
                                 price, vol, tnvr,
                                 event, buy, agr);
#endif
        };

        static auto create(time_type time, id_type cli_id, id_type ins_id, id_type seq_id,
                           quant_type price, quant_type vol, quant_type tnvr,
                           RecordEvent event, bool is_buy, bool is_agr)
        {
            return RecordT{time, cli_id, ins_id, seq_id,
                           price, vol, tnvr,
                           event, is_buy, is_agr};
        }

        /**
         * @brief Callback on new event record
         *
         * @param cli_id client id
         * @param ins_id instrument id
         * @param rec new event record
         */
        virtual void on_record(id_type cli_id, id_type ins_id, const RecordT &rec)
        {
        }

        /**
         * @brief Callback on position update
         *
         * @param cli_id client id
         * @param ins_id instrument id
         * @param pos updated position
         */
        virtual void on_position(id_type cli_id, id_type ins_id, const pos_rec &pos)
        {
        }

        /**
         * @brief Callback on funds update
         *
         * @param cli_id client id
         * @param ins_id instrument id that triggered funds update
         * @param funds updated funds
         */
        virtual void on_funds(id_type cli_id, id_type ins_id, const funds_rec &funds)
        {
        }

        /**
         * @brief Callback on error
         *
         * @param cli_id client id
         * @param ins_id instrument id that triggered error
         * @param info information about the error
         */
        virtual void on_error(id_type cli_id, id_type ins_id, const std::string &info)
        {
        }

        virtual ~BaseRecord() = default;
    };
}

#ifdef PUNCH_MSGPACK
    MSGPACK_ADD_ENUM(mdtx::punch::tradesim::RecordEvent);
#endif
